
#ifndef H_BTL_SPECTRAL_API_H
#define H_BTL_SPECTRAL_API_H

#include "btl_bep.h"

#define blt_sensor_connected_status_test btl_sensor_connected_status_test

typedef enum {
    BTL_SCS_OK = 0,
    BTL_SCS_SPI_ERR,
    BTL_SCS_ID_ERR,
    BTL_SCS_RST_ERR,
    BTL_SCS_INT_ERR,
} btl_scs_t;

typedef enum {
    BTL_SENSOR_POWER_ON  = 0,  // 打开电源
    BTL_SENSOR_POWER_OFF = 1,  // 关闭电源
} btl_power_mode_t;

extern void (*btl_sensor_power_control)(btl_power_mode_t);

extern btl_rc_t btl_create_multitemplate_ex(const PBL_TEMPLATE pblTemplates[],  //[in] 待合并指纹模板
                                            unsigned char nNbrOfTemplates,      //[in] 待合并指纹模板数量
                                            unsigned char fix_num,              //[in] 固定不可更新的模板数量
                                            PBL_TEMPLATE pblMultiTemplates);  //[out]合并后的多模板数组，注意：用户一定要及时释放，否则可能引起内存错乱等未知错误。

/*
匹配,支持一对一或一对多个模板比对
*/
extern btl_rc_t btl_verify_pair(PBL_TEMPLATE pblTemplate,              //[in] 待匹配模板
                                PBL_TEMPLATE blMultiTemplatesArray[],  //[in] 待匹配模板数组
                                int nNbrOfMultiTemplates,              //[in] 数组大小
                                int* pMatchIndex                       //[out] 匹配成功的模板序号
);

///*
//匹配,不同模板使用不同的安全等级
//*/
//extern btl_rc_t btl_verify_ex(PBL_TEMPLATE_EX blMultiTemplatesExArray, int nNbrOfMultiTemplates, int* pMatchIndex);

/***********************************************************************
 * @name    btl_capture_image
 * @brief   采集原图（有AGC，不判断手指抬起，不做任何预处理）
 * @param   is_for_quality_checked：[in] 是否用于图像质量测试，1为是，0为否
 * @retval  btl_rc_t 如果检测到手指按压则采图，返回采图状态；否则返回BTL_RC_FINGER_DETECT_ERR
 **********************************************************************/
extern btl_rc_t btl_capture_image(unsigned char is_for_quality_checked);

/***********************************************************************
 * @name    btl_get_similarity_score
 * @brief   获取单个模板与多个模板的相似度分数

 * @param   multi_templates：[in] 已经注册多模板指针
 * @param   single_Template：[in] 待校验模板指针
 * @param   score：[out] 输出分数值指针
 * @retval  btl_rc_t
 **********************************************************************/
extern btl_rc_t btl_get_similarity_score(const PBL_TEMPLATE multi_templates, const PBL_TEMPLATE single_Template, unsigned short* score);

/***********************************************************************
 * @name    btl_get_overlap_area
 * @brief   获取单个模板与多个模板的重合面积，仅R4X算法版本支持

 * @param   multi_templates：[in] 已经注册多模板指针
 * @param   single_Template：[in] 待校验模板指针
 * @param   overlap_area：   [out] 输出重合面积，范围[0,100]
 * @retval  btl_rc_t
 **********************************************************************/
extern btl_rc_t btl_get_overlap_area(const PBL_TEMPLATE multi_templates, const PBL_TEMPLATE single_Template, int* overlap_area);

/***********************************************************************
 * @name    btl_decode_multiTemplates
 * @brief   解码多模板，返回子模板数组

 * @param   pblMultiTemplates: [in] 多模板数据
 * @param   pblSubTemplates: [out] 返回子模板数组
 * @param   nNbrOfSubtemplates: [out] 子模板数量
 * @retval  btl_rc_t
 **********************************************************************/
extern btl_rc_t btl_decode_multiTemplates(const PBL_TEMPLATE pblMultiTemplates, PBL_TEMPLATE** pblSubTemplates, unsigned char* nNbrOfSubtemplates);

/***********************************************************************
 * @name    btl_delete_subtemplates
 * @brief   释放子模板数组占用的资源

 * @param   pblSubTemplates: [in] 子模板指针数组,pblSubTemplates本身也会被释放，所以其所占用内存需要malloc
 * @param   nNbrOfSubtemplates: [in] 子模板数量
 * @retval  btl_rc_t
 **********************************************************************/
extern btl_rc_t btl_delete_subtemplates(PBL_TEMPLATE* pblSubTemplates, unsigned char nNbrOfSubtemplates);

/***********************************************************************
 * @name    btl_get_score_by_subtemplates
 * @brief   子模板间的相似程度分

 * @param   pblSubTemplates:    [in] 子模板数组
 * @param   nNbrOfSubTemplates: [in] 子模板数量
 * @retval  pSimilarityScores:  [in/out] 传入元素个为nNbrOfSubTemplates的数组，由内部填充相似分值
 **********************************************************************/
extern btl_rc_t btl_get_score_by_subtemplates(PBL_TEMPLATE* pblSubTemplates, unsigned char nNbrOfSubTemplates, unsigned short* pSimilarityScores);

/***********************************************************************
 * @name    btl_verify_speed
 * @brief   单个模板与多模板比对

 * @param   pblMultiTemplates:       [in] 多模板数据
 * @param   nNbrOfMultiTemplates:    [in] 已录入模板数量
 * @param   nFarAccepted:            [in] 比对安全等级
 * @param   nMaxNbrOfSubTempaltes：  [in] 每个多模板中参与比对的最大子模板数
 * @param   pMatchIndex：            [out] 匹配成功的模板序号，从0开始，-1表示匹配失败
 * @retval  btl_rc_t
 **********************************************************************/
extern btl_rc_t btl_verify_speed(const PBL_TEMPLATE* pblMultiTemplates,  //[in] 已录入多模板数组
                                 unsigned char nNbrOfMultiTemplates,     //[in] 已录入模板数量
                                 int nFarAccepted,                       //[in] FAR
                                 unsigned char nMaxNbrOfSubTempaltes,    //[in] 每个多模板中参与比对的最大子模板数
                                 int* pMatchIndex                        //[out] 匹配成功的模板序号，从0开始，-1表示匹配失败
);

/***********************************************************************
 * @name    btl_image_enhance
 * @brief   图像增强

 * @retval  btl_rc_t
 **********************************************************************/
extern btl_rc_t btl_image_enhance(void);

/***********************************************************************
 * @name    btl_get_badpixels_count
 * @brief   基于原图，获取坏点个数，旧版原型是int btl_getBadLinePixelsNum(int* nBadPixelsNum);
  （BTL_GET_IMAGE_MODE模式下，配置btl_get_config()->ImageEnhance = 0; btl_get_config()->image_modify_control = 0;得到的即是原图）
 * @param   nBadLineThre:   [in] 坏线检测阈值，推荐值是50，设置成0则不检测坏线
 * @param   nBadPointThre:  [in] 坏点检测阈值，推荐值是18，设置成0则不检测坏点
 * @param   nBadPixelsNum:  [out] 返回坏点个数
 * @retval  int          ：  0表示成功，else表示失败
 **********************************************************************/
extern int btl_get_badpixels_count(int nBadLineThre, int nBadPointThre, int* nBadPixelsNum);

/***********************************************************************
 * @name    btl_computeSNR
 * @brief   基于原图（使用btl_capture_image采集），计算图像信噪比
 * @param   pSNR   :  [out] 信噪比
 * @param   pSignal:  [out] 信号量
 * @param   pNoise :  [out] 噪声量

 * @retval  int    ： 0表示成功，else表示失败
 **********************************************************************/
extern int btl_computeSNR(unsigned char* pSNR, unsigned char* pSignal, unsigned char* pNoise);

/***********************************************************************
 * @name    btl_get_cap
 * @brief  获取图像的电容值

 * @param   nCap   :  [out] 输出的电容值
 * @retval  btl_rc_t    ： BTL_RC_OK表示成功，else表示失败
 **********************************************************************/
extern btl_rc_t btl_get_cap(short* nCap);

/***********************************************************************
 * @name    btl_add_cap
 * @brief   添加电容值

 * @param   nCap   :  [in] 需要添加的电容值
 * @retval  btl_rc_t  ： BTL_RC_OK表示成功，else表示失败
 **********************************************************************/
extern btl_rc_t btl_add_cap(short nCap);

/***********************************************************************
 * @name    btl_finalize_cap
 * @brief   获取最大的电容值

 * @param   nMaxCap   :  [out] 输出的最大电容值
 * @retval  btl_rc_t  ： 0表示成功，else表示失败
 **********************************************************************/
extern btl_rc_t btl_finalize_cap(short* nMaxCap);

/***********************************************************************
 * @name    btl_force_image_without_agc
 * @brief   强制采图，不做AGC调整，保留原始数据，可以用于测试灵敏度

 * @retval  btl_rc_t     ： BTL_RC_OK表示成功，else表示失败
 **********************************************************************/
extern btl_rc_t btl_force_image_without_agc(void);

/***********************************************************************
 * @name    btl_get_image_center_value
 * @brief   获取图像48*48中心区域的灰度均值，量产检测灵敏度用
 * @param   nValue       :  [out]返回图像灰度均值
 * @retval  btl_rc_t     ： BTL_RC_OK表示成功，else表示失败
 **********************************************************************/
extern btl_rc_t btl_get_image_center_value(unsigned char* nValue);

/***********************************************************************
 * @name    btl_force_image_without_print
 * @brief   强制多次采图，不上传图像数据，供一体化模组量产测试采图功耗用

 * @param   times             :  [in] 采图次数
 * @param   nCapInterval      :  [in] 采图间隔，单位ms
 * @retval                    ： 采图出错的次数
 **********************************************************************/
extern int btl_force_image_without_print(int times, int nCapInterval);

/***********************************************************************
 * @name    btl_read_register
 * @brief   获取某个寄存器的值

 * @param   nRegAddr   :  [in] 寄存器地址
 * @param   pData      :  [out] 返回寄存器值
 * @retval  btl_rc_t   ： BTL_RC_OK表示成功，else表示失败
 **********************************************************************/
extern btl_rc_t btl_read_register(unsigned char nRegAddr, unsigned char* pData);

/***********************************************************************
 * @name    btl_write_register
 * @brief   设置某个寄存器的值

 * @param   nRegAddr   :  [in] 寄存器地址
 * @param   nData      :  [in] 寄存器值
 * @retval  btl_rc_t   ： BTL_RC_OK表示成功，else表示失败
 **********************************************************************/
extern btl_rc_t btl_write_register(unsigned char nRegAddr, unsigned char nData);

/***********************************************************************
 * @name    btl_get_base_image
 * @brief   采集BASE图像，供后期采图减BASE使用
 * @param   nDevThreshold     :  [in] 图像方差阈值，推荐值300
 * @param   nSnrThreshold     :  [in] 图像信噪比阈值，推荐值15
 * @param   nSignalThreshold  :  [in] 图像信号量阈值，推荐值20
 * @param   nMeanValue        :  [out] 返回图像的灰度均值
 * @retval  btl_rc_t
 ：返回BTL_RC_OK之后，通过btl_get_image_data()、btl_get_image_width()、btl_get_image_height()接口获取图像数据
 * @example
unsigned char nBaseImgMeanValue = 0;
if(BTL_RC_OK == btl_get_base_image(300,15,20,&nBaseImgMeanValue))
{
    //存储灰度值和图像数据
    flash_write_base_image(nBaseImgMeanValue, btl_get_image_data(), btl_get_image_width(), btl_get_image_height());
}
 **********************************************************************/
extern btl_rc_t btl_get_base_image(int nDevThreshold, unsigned char nSnrThreshold, unsigned char nSignalThreshold, unsigned char* nMeanValue);

#ifndef _FINGER_PRINT_STRUCT_
#define _FINGER_PRINT_STRUCT_

typedef struct _TBaseInfo {
    unsigned short* pImageSumBuffer;  // 准备用于合成BASE的图像像素累加和
    unsigned int image_count_cur;     // 准备用于合成BASE的图像数量
    unsigned char* pBaseImage;        // 已经合成的BASE
    unsigned int image_count_total;   // 合成BASE所使用的图像总数
} TBaseInfo;

typedef struct _TImageInfo {
    unsigned char* srcImg;       // 图像数据
    int nWidth;                  // 宽
    int nHeight;                 // 高
    void (*free_buffer)(void*);  // 如果提供了此接口，则函数在使用完srcImg之后就会调用它来释放资源
} TImageInfo;

#endif

/***********************************************************************
 * @name    btl_update_base_info
 * @brief   使用原始图像更新base信息

 * @param   pImgInfo     :  [in] 原始图像数据
 * @param   pBaseInfoOld :  [in] 旧的BASE信息
 * @param   pBaseInfoNew :  [out] 新的BASE信息
 * @retval  btl_rc_t   ：
 * @example
 **********************************************************************/
extern btl_rc_t btl_update_base_info(TImageInfo* pImgInfo, const TBaseInfo* pBaseInfoOld, TBaseInfo* pBaseInfoNew);

/***********************************************************************
 * @name    btl_minus_base_image
 * @brief   原始图像去底噪

 * @param   srcImg     :  [in] 原始图像数据
 * @param   pImageBase :  [in] BASE图像
 * @param   nWidth     :  [in] 图像宽
 * @param   nHeight    :  [in] 图像高
 * @param   nBaseMean  :  [in] BASE图像的灰度均值，传入0则由内部计算
 * @retval  btl_rc_t   ：
 * @example
int customer_image_preproc_2(unsigned char* image, int w, int h)
{
  unsigned char nBaseImgMeanValue = 0;
    unsigned char* pBaseImage = 0;

    customer_read_base_info_mr(&BaseInfoOld);

    if(BaseInfoOld.pBaseImage)
    {
      nBaseImgMeanValue = (unsigned char)customer_get_mean_of_image(image, w, h);  //可以在提取BASE的时候计算并存入flash，以便节省时间
        btl_minus_base_image(image, BaseInfoOld.pBaseImage, w, h, nBaseImgMeanValue);
    }
    return 0;
}
//在btl_bep_init之前给btl_outside_image_preproc_2赋值
btl_outside_image_preproc_2 = customer_image_preproc_2;
 **********************************************************************/
extern btl_rc_t btl_minus_base_image(unsigned char* srcImg, const unsigned char* pImageBase, int nWidth, int nHeight, unsigned char nBaseMean);

/***********************************************************************
 * @name    btl_sensor_connected_status_test
 * @brief   Sensor连接状态检查，包括SPI、RST、INT和Chip ID核验

 * @retval  btl_scs_t   ：
 **********************************************************************/
extern btl_scs_t btl_sensor_connected_status_test(void);

/***********************************************************************
 * @name    btl_disable_finger_up_once
 * @brief   单次取消手指抬起检测

 * @retval  void
 **********************************************************************/
extern void btl_disable_finger_up_once(void);

/***********************************************************************
 * @name    btl_update_definite_templates
 * @brief   update definited template into multitamplate

 * @param   pblTemplate            :  [in] the new definited template
 * @param   pblMultiTemplates      :  [in] the old multitamplates
 * @param   pblUpdateMultiTemplates:  [out] the outcome
 * @retval  btl_rc_t   ：
 **********************************************************************/
extern int btl_update_definite_templates(const PBL_TEMPLATE pblTemplate, const PBL_TEMPLATE pblMultiTemplates, PBL_TEMPLATE pblUpdateMultiTemplates);

typedef enum {
    BTL_ACTION_CAP_SMALL,
    BTL_ACTION_CAP_LARGE,
} btl_action_t;

typedef enum {
    BTL_STEP_START,
    BTL_STEP_GOON,
    BTL_STEP_END,
} btl_step_t;
/***********************************************************************
 * @name    btl_action_step
 * @brief   接收程序执行进度

 * @param   action  :  [in] 行为
 * @param   step    :  [in] 步骤
 * @retval  void    ：
 **********************************************************************/
extern void (*btl_action_step)(btl_action_t action, btl_step_t step);

/***********************************************************************
 * @name    btl_set_enroll_screen_setttings
 * @brief   V3.x.x.x或V5.x.x.x版本，在使用btl_enrollment进行注册时，
            需使用此接口对已注册模板进行查重，进入注册前调用一次即可。

 * @param   pSettings  :  [in] 见结构体
 * @retval  btl_rc_t
 * @example
#if (0)//V0.x.x.x 或 V1.x.x.x版本
  work.MatchIndex = -1;
  btl_rerult = btl_verify(pblMultiTemplatesArray,num_fingers,&work.MatchIndex);
  if((btl_rerult==BTL_RC_OK) && (work.MatchIndex >= 0)){
    //跟已注册ID匹配成功
  };
#else//V3.x.x.x 或 V5.x.x.x版本
  BL_EMBEDDED_ENROLL_SCREEN_SETTINGS_t enroll_screen_setttings = {0};
  enroll_screen_setttings.nNbrOfMultiTemplates = num_fingers;
  enroll_screen_setttings.pblMultiTemplates = pblMultiTemplatesArray;
  enroll_screen_setttings.max_verify_count_one_time = 0; //get_storage_setting()->max_verify_count_one_time;
  btl_set_enroll_screen_setttings(&enroll_screen_setttings);
  //如果跟已注册ID匹配成功，则btl_enrollment会返回BTL_RC_EXIST_ENROLL_ID
#endif
***********************************************************************/
extern btl_rc_t btl_set_enroll_screen_setttings(BL_EMBEDDED_ENROLL_SCREEN_SETTINGS_t* pSettings);

/***********************************************************************
 * @name    btl_printf
 * @brief   内部log打印接口

 * @param   fmt    :  [in] 字符
 * @param   ...    :  [in] 参数
 * @retval  void    ：
 * @example
   btl_printf = printf;
   btl_get_config()->log_switch = 0xFF; // print all log
 **********************************************************************/
extern int (*btl_printf)(const char* fmt, ...);
/***********************************************************************
 * @name    bl_Alg_ExternalStorageSaveData
 * @brief   保存算法的某些数据，如SPD数据

 * @param   data_type    :  [in] 数据类型
 * @param   data         :  [in] 数据地址
 * @param   data_size    :  [in] 数据长度
 * @retval  int    ： 返回0表示保存成功
 **********************************************************************/
extern int (*bl_Alg_ExternalStorageSaveData)(unsigned char data_type, const unsigned char* data, unsigned int data_size);

/***********************************************************************
 * @name    bl_Alg_ExternalStorageLoadData
 * @brief   加载算法的某些数据，如SPD数据

 * @param   data_type    :  [in] 数据类型
 * @param   data         :  [out] 返回数据地址
 * @param   data_size    :  [out] 返回数据长度
 * @retval  int    ： 返回0表示加载成功
 **********************************************************************/
extern int (*bl_Alg_ExternalStorageLoadData)(unsigned char data_type, unsigned char** data, unsigned int* data_size);

/***********************************************************************
 * @name    btl_multi_sensor_get_total_count
 * @brief   支持挂多个sensor的回调函数，获取sensor的数量，最多支持2个，放在btl_bep_init之前实现

 * @param   total_count    :  [out] 返回sensor的总数量
 * @retval  void
 * @example
  void customer_multi_sensor_get_total_count(unsigned char* total_count)
  {
    *total_count = 2;
  }
  //在btl_bep_init之前赋值
  btl_multi_sensor_get_total_count = customer_multi_sensor_get_total_count;
 **********************************************************************/
extern void (*btl_multi_sensor_get_total_count)(unsigned char* total_count);

/***********************************************************************
 * @name    btl_multi_sensor_set_active_index
 * @brief   支持挂多个sensor的回调函数，设置当前激活的sensor序号，放在btl_bep_init之前实现

 * @param   active_index   :  [in] 当前激活的sensor序号，从0开始
 * @retval  void
 * @example
  unsigned char g_btl_sensor_active_index = 0; //RST、CS和SPI读写操作中根据此index来控制对应的sensor
  void customer_multi_sensor_set_active_index(unsigned char active_index)
  {
    g_btl_sensor_active_index = active_index;
  }
  //在btl_bep_init之前赋值
  btl_multi_sensor_set_active_index = customer_multi_sensor_set_active_index;
 **********************************************************************/
extern void (*btl_multi_sensor_set_active_index)(unsigned char active_index);

/***********************************************************************
 * @name    btl_test_xxxx_latency
 * @brief   MCU运算能力测试

 * @param   num   :  [in] 循环次数
 * @retval
 测试接口                                 国芯4201S(200MHz)     国民N32G4FR(128MHz)
 btl_test_addition_latency(1000)
 btl_test_integer_multiplication_latency(1000)   198ms                313ms
 btl_test_multiplication_latency(100)           479ms                2341ms
 btl_test_integer_division_latency(1000)         247ms                392ms
 btl_test_division_latency(100)                 262ms                405ms
 **********************************************************************/
extern int btl_test_addition_latency(int num);
extern int btl_test_integer_multiplication_latency(int num);
extern double btl_test_multiplication_latency(int num);
extern int btl_test_integer_division_latency(int num);
extern double btl_test_division_latency(int num);
//////////////////////////////////////////////////
#endif
